﻿#include "rollingbox.h"

RollingBox::RollingBox(QWidget *parent) : QWidget(parent)
  , m_minRange(2000)
  , m_maxRange(2030)
  , m_value(2024)
  , m_showDirection(SD_VERTICAL)
  , isDragging(false)
  , m_deviation(0)
  , m_mouseSrcPos(0)
  , m_numSize(6)
{
    m_frontColor = QColor(34, 34, 34, 255);
    homingAni  = new QPropertyAnimation(this, "deviation");
    //定义动画持续时间
    homingAni->setDuration(300);
    //设置动画效果
    homingAni->setEasingCurve(QEasingCurve::OutQuad);
}

void RollingBox::setRange(int min, int max)
{
    if (min > max)
        return ;
    m_minRange = min;
    m_maxRange = max;

    if(m_value < min)
        m_value = min;
    if(m_value > max)
        m_value = max;

    //计算字符尺寸
    m_numSize = 3;
    int temp = m_maxRange;
    while(temp > 0)
    {
        temp /= 10;
        m_numSize++;
    }

    repaint();
}

void RollingBox::setDirection(RollingBox::ShowDirection dir)
{
    m_showDirection = dir;
    repaint();
}

void RollingBox::setValue(int value)
{
    if (value > m_maxRange)
        value = m_maxRange;
    if (value < m_minRange)
        value = m_minRange;
    m_value = value;
}

void RollingBox::setFrontColor(const QColor color)
{
    m_frontColor = color;
    repaint();
}

/*
 * 鼠标按住事件
 */
void RollingBox::mousePressEvent(QMouseEvent *e)
{
    homingAni->stop();
    isDragging = true;
    m_mouseSrcPos = (m_showDirection == SD_HORIZONTAL)? (e->pos().x()):(e->pos().y());
}

/*
 * 鼠标移动事件
 */
void RollingBox::mouseMoveEvent(QMouseEvent *e)
{
    if(!isDragging)
        return ;

    int pos = (m_showDirection == SD_HORIZONTAL)? (e->pos().x()) : (e->pos().y());
    int length = (m_showDirection == SD_HORIZONTAL)? (width()) : (height());

    m_deviation = pos - m_mouseSrcPos;

    //若移动速度过快时进行限制
    if(m_deviation > (length - 1) / 4)
        m_deviation = (length - 1) / 4;
    else if(m_deviation < -(length - 1) / 4)
        m_deviation = -(length - 1) / 4;

    emit deviationChangeSign((float)m_deviation / ((length - 1) / 4));
    repaint();
}

/*
 * 鼠标松开事件
 */
void RollingBox::mouseReleaseEvent(QMouseEvent *)
{
    if(!isDragging)
        return ;
    isDragging = false;
    homing();
}

void RollingBox::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing, true);

    int measurement = (m_showDirection == SD_HORIZONTAL)? (width()-1) : (height()-1);

    if(m_deviation >= measurement/4)
    {
        m_mouseSrcPos   += measurement/4;
        m_deviation     -= measurement/4;
        m_value  -= 1;
        if (m_value < m_minRange)
            m_value = m_maxRange;
    }
    if(m_deviation <= -measurement/4)
    {
        m_mouseSrcPos   -= measurement/4;
        m_deviation     += measurement/4;
        m_value  += 1;
        if (m_value > m_maxRange)
            m_value = m_minRange;
    }

    //中间数字
    paintNum(painter, m_value, m_deviation);

    //两侧数字1
    int temp = m_value - 1;
    if (temp < m_minRange)
        temp = m_maxRange;
    paintNum(painter, temp, m_deviation - measurement / 3);
    temp = m_value + 1;
    if (temp > m_maxRange)
        temp = m_minRange;
    paintNum(painter, temp, m_deviation + measurement / 3);

    //两侧数字2,超出则不显示
    if(m_deviation >= 0)
    {
        temp = m_value - 2;
        if (temp == m_minRange - 1)
            temp = m_maxRange;
        else if (temp == m_minRange - 2)
            temp = m_maxRange - 1;
        else if (temp < m_minRange)
            temp = m_maxRange - 2;
        paintNum(painter, temp, m_deviation - measurement / 2);
    }
    if(m_deviation <= 0)
    {
        temp = m_value + 2;
        if (temp == m_maxRange + 1)
            temp = m_minRange;
        else if (temp == m_maxRange + 2)
            temp = m_minRange + 1;
        else if (temp > m_maxRange)
            temp = m_minRange + 2;
        paintNum(painter, temp, m_deviation + measurement / 2);
    }
    paintLine(painter);
}

/*
 * 绘制数字
 */
void RollingBox::paintNum(QPainter &painter,int num,int deviation)
{
    painter.save();

    int measurement = (m_showDirection == SD_HORIZONTAL)? (width()-1) : (height()-1);

    int size = (measurement - qAbs(deviation)) / m_numSize;
    //颜色透明度
    int transparency = 255 - 510 * qAbs(deviation) / measurement;
    if (transparency < 0)
        transparency = 0;
    int len = measurement / 2 - 3 * qAbs(deviation) / 4;
    int pos = measurement / 2 + deviation - len / 2;

    QFont font;
    font.setPixelSize(size);
    painter.setFont(font);
    m_frontColor.setAlpha(transparency);
    painter.setPen(m_frontColor);

    if (m_showDirection == SD_HORIZONTAL)
        painter.drawText(QRectF(pos, 0, len, height()-1), Qt::AlignCenter, QString::number(num));
    else
        painter.drawText(QRectF(0, pos, width()-1, len), Qt::AlignCenter, QString::number(num));

    painter.restore();
}

/*
 * 画线
 */
void RollingBox::paintLine(QPainter &painter)
{
    painter.save();

    QPen pen;
    m_frontColor.setAlpha(120);
    pen.setBrush(m_frontColor);
    int lineWidth = 2;
    pen.setWidth(lineWidth);
    pen.setCapStyle(Qt::RoundCap);
    pen.setStyle(Qt::SolidLine);
    painter.setPen(pen);

    int space = 10;
    if(m_showDirection == SD_HORIZONTAL)
    {
        int up_down_space = height() / 10;
        QPoint left_up=QPoint(space + (width() - space * 2) / 3, up_down_space);
        QPoint left_down = QPoint(space + (width() - space * 2) / 3, height() - up_down_space);
        QPoint right_up = QPoint(space + ((width() - space * 2) / 3) * 2, up_down_space);
        QPoint right_down = QPoint(space + ((width() - space * 2) / 3) * 2, height() - up_down_space);
        painter.drawLine(left_up, left_down);
        painter.drawLine(right_up, right_down);
    }else{
        int up_down_space = width() / 10;
        QPoint left_up = QPoint(up_down_space, space + (height() - space * 2) / 3);
        QPoint left_down = QPoint(2 * space + (width() - space * 2) - up_down_space, space + (height() - space * 2) / 3);
        QPoint right_up = QPoint(up_down_space, space + ((height() - space * 2) / 3) * 2);
        QPoint right_down = QPoint(2 * space + (width() - space * 2) - up_down_space, space + ((height() - space * 2) / 3) * 2);
        painter.drawLine(left_up, left_down);
        painter.drawLine(right_up, right_down);
    }
    painter.drawRoundedRect(1, 1, width() - lineWidth, height() - lineWidth, 6, 6);

    painter.restore();
}

/*
 * 将数字矫正到中心
 */
void RollingBox::homing()
{
    int measurement = (m_showDirection == SD_HORIZONTAL)?(width()):(height());
    if(m_deviation > measurement / 8)
    {
        homingAni->setStartValue((measurement - 1) / 8 - m_deviation);
        homingAni->setEndValue(0);
        m_value--;
        if (m_value < m_minRange)
            m_value = m_maxRange;
    }
    else if(m_deviation < -measurement / 8)
    {
        homingAni->setStartValue(-(measurement - 1) / 8 - m_deviation);
        homingAni->setEndValue(0);
        m_value++;
        if (m_value > m_maxRange)
            m_value = m_minRange;
    }else{
        homingAni->setStartValue(m_deviation);
        homingAni->setEndValue(0);
    }
    emit valueChangedSign(m_value);
    homingAni->start();
}

int RollingBox::readDeviation()
{
    return m_deviation;
}

void RollingBox::setDeviation(int n)
{
    m_deviation = n;
    repaint();
}
